package com.wzb.mybatisplus.bitaction.electrumaction.two;

import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.math.ec.ECPoint;

public class CompressedToUncompressedPublicKey {

    /**
     * 将压缩公钥(66字符)转换为未压缩公钥(130字符)
     */
    public static String compressedToUncompressed(String compressedPubKey) {
        try {
            // 验证输入格式
            if (compressedPubKey == null || compressedPubKey.length() != 66) {
                throw new IllegalArgumentException("压缩公钥必须是66个十六进制字符");
            }

            if (!compressedPubKey.matches("^[0-9A-Fa-f]{66}$")) {
                throw new IllegalArgumentException("包含无效的十六进制字符");
            }

            String prefix = compressedPubKey.substring(0, 2);
            if (!"02".equals(prefix) && !"03".equals(prefix)) {
                throw new IllegalArgumentException("压缩公钥必须以02或03开头");
            }

            // 获取secp256k1曲线参数
            ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256k1");

            // 将十六进制字符串转换为字节数组
            byte[] compressedBytes = hexStringToByteArray(compressedPubKey);

            // 解码为ECPoint（Bouncy Castle自动处理解压）
            ECPoint point = spec.getCurve().decodePoint(compressedBytes);

            // 获取未压缩格式
            byte[] uncompressedBytes = point.getEncoded(false);

            // 转换为十六进制字符串
            String uncompressedPubKey = byteArrayToHexString(uncompressedBytes).toUpperCase();

            // 验证结果格式
            if (!uncompressedPubKey.startsWith("04") || uncompressedPubKey.length() != 130) {
                throw new RuntimeException("生成的未压缩公钥格式无效");
            }

            return uncompressedPubKey;

        } catch (Exception e) {
            throw new RuntimeException("转换失败: " + e.getMessage(), e);
        }
    }

    /**
     * 直接获取公钥的(x,y)坐标
     */
    public static String[] getPublicKeyCoordinates(String compressedPubKey) {
        try {
            ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256k1");
            byte[] compressedBytes = hexStringToByteArray(compressedPubKey);
            ECPoint point = spec.getCurve().decodePoint(compressedBytes).normalize();

            String x = point.getAffineXCoord().toBigInteger().toString(16).toUpperCase();
            String y = point.getAffineYCoord().toBigInteger().toString(16).toUpperCase();

            // 补齐64位
            x = String.format("%64s", x).replace(' ', '0');
            y = String.format("%64s", y).replace(' ', '0');

            return new String[]{x, y};

        } catch (Exception e) {
            throw new RuntimeException("获取坐标失败", e);
        }
    }

    // 工具方法
    public static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                    + Character.digit(s.charAt(i+1), 16));
        }
        return data;
    }

    public static String byteArrayToHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }

    public static void main(String[] args) {
        // 示例压缩公钥（66字符）
        String[] compressedPublicKeys = {
                "0250863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B2352",
                "03A34B99F22C790C4E36B2B3C2C35A36DB06226E41C692FC82B8B56AC1C540C5BD"
        };

        for (String compressedKey : compressedPublicKeys) {
            try {
                System.out.println("=== 公钥转换 ===");
                System.out.println("压缩公钥 (66字符): " + compressedKey);
                System.out.println("前缀: " + compressedKey.substring(0, 2));

                // 获取坐标
                String[] coordinates = getPublicKeyCoordinates(compressedKey);
                System.out.println("X坐标 (64字符): " + coordinates[0]);
                System.out.println("Y坐标 (64字符): " + coordinates[1]);

                // 转换为未压缩格式
                String uncompressedKey = compressedToUncompressed(compressedKey);
                System.out.println("未压缩公钥 (130字符): " + uncompressedKey);
                System.out.println("前缀: " + uncompressedKey.substring(0, 2));
                System.out.println("长度验证: " + uncompressedKey.length());

                System.out.println();

            } catch (Exception e) {
                System.err.println("处理失败: " + e.getMessage());
            }
        }
    }
}